# 引入Student的类
from Student.models import Student
from Student.models import *
# 引入JsonResponse模块
from django.http import JsonResponse
# 导入json模块
import json
# 导入Q查询
from django.db.models import Q
# 导入uuid类
import uuid
# 导入哈希库
import hashlib
# 导入Setting
from django.conf import settings
# 导入os
import os
# 引入处理Excel模块
import openpyxl
from School.serializers import *
from School.serializers import ApplicationSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
import datetime
import jwt
import logging

from .pagination import CustomPagination


class LoginView(APIView):
    # 意味着不需要携带token就可以访问这个接口当[空]时
    authentication_classes = []

    def post(self, request):
        # 从请求中获取用户名和密码
        username = request.data.get('username')
        password = request.data.get('password')

        user_object = School.objects.filter(account=username, password=password).first()
        if not user_object:
            return JsonResponse({'code': 1000, 'error': "用户名或密码错误"})
        salt = settings.SECRET_KEY
        # 构造header（不写默认也是它）
        headers = {
            'typ': 'JWT',
            'alg': 'HS256'
        }
        # 构造payload
        payload = {
            'user_id': user_object.account,
            'username': user_object.name,
            'id': user_object.id,
            'exp': datetime.datetime.now(datetime.UTC) + datetime.timedelta(hours=24),
        }
        token = jwt.encode(payload=payload, key=salt, algorithm='HS256', headers=headers)
        print('创建的token', token)

        return Response({'code': 1001, 'data': token})


class identy(APIView):

    def get(self, request):
        payload = request.user
        name = payload['username']
        school = School.objects.get(name=name)
        image = school.image
        id = school.id
        if school.ismanager:
            print(f"{school.name} 是一个管理员。")
            return JsonResponse({'is': 1, 'name': school.name, 'image': image, 'id': id})
        else:
            return JsonResponse({'name': school.name})


class StudentListView(APIView):
    pagination_class = CustomPagination  # 添加自定义分页器的类

    def get(self, request):
        try:
            payload = request.user
            username = payload['username']
            id = payload['id']
            school_id = payload['id']
            print(username)
            print(id)

            # 使用ORM获取所有学生信息
            queryset = Student.objects.filter(school_id=school_id)

            # 实例化自定义分页器
            paginator = self.pagination_class()
            paginated_queryset = paginator.paginate_queryset(queryset, request)

            # 使用序列化器序列化查询集
            serializer = StudentSerializer(paginated_queryset, many=True)

            # 返回分页后的数据
            return paginator.get_paginated_response(serializer.data)

        except Exception as e:
            # 如果出现异常，返回错误信息
            return Response({'code': 0, 'msg': "获取学生信息出现异常，具体错误：" + str(e)})

def query_students(request):
    """查询学生信息"""
    try:
        data = json.loads(request.body.decode('utf-8'))
        # 使用ORM获取满足条件的学生信息 并把对象转为字典格式
        obj_students = Student.objects.filter(
            Q(sno__icontains=data['inputstr']) |
            Q(name__icontains=data['inputstr']) |
            Q(gender__icontains=data['inputstr']) |
            Q(mobile__icontains=data['inputstr']) |
            Q(address__icontains=data['inputstr'])
        ).values()

        # 把外层的容器转为List
        students = list(obj_students)

        # 返回
        return JsonResponse({'code': 1, 'data': students})

    except json.JSONDecodeError as e:
        print(e)
        return JsonResponse({'code': 0, 'msg': "JSON解析错误：" + str(e)})

    except KeyError as e:
        print(e)
        return JsonResponse({'code': 0, 'msg': "缺少必要的字段：" + str(e)})

    except Exception as e:
        print(e)
        return JsonResponse({'code': 0, 'msg': "查询学生信息出现异常，具体错误：" + str(e)})


def is_exists_sno(request):
    """判断学号是否存在"""
    # 接收传递过来的学号
    data = json.loads(request.body.decode('utf-8'))
    # 进行校验
    try:
        obj_students = Student.objects.filter(sno=data['sno'])
        if obj_students.count() == 0:
            return JsonResponse({'code': 1, 'exists': False})
        else:
            return JsonResponse({'code': 1, 'exists': True})
    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "校验学号失败，具体原因：" + str(e)})


def add_student(request):
    """添加学生到数据库"""
    # 接收前端传递过来的值
    data = json.loads(request.body.decode("utf-8"))
    try:
        # 添加到数据库
        obj_student = Student(sno=data['sno'], name=data['name'], gender=data['gender'],
                              birthday=data['birthday'], mobile=data['mobile'],
                              email=data['email'], address=data['address'], image=data['image'],
                              school_id=data['school_id'])
        # 执行添加
        obj_student.save()
        # 使用ORM获取所有学生信息 并把对象转为字典格式
        obj_students = Student.objects.all().values()
        # 把外层的容器转为List
        students = list(obj_students)
        # 返回
        return JsonResponse({'code': 1, 'data': students})
    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "添加到数据库出现异常，具体原因：" + str(e)})


def update_student(request):
    """修改学生到数据库"""
    # 接收前端传递过来的值
    data = json.loads(request.body.decode("utf-8"))
    try:
        # 查找到要修改的学生信息
        obj_student = Student.objects.get(sno=data['sno'])
        # 依次修改
        obj_student.name = data['name']
        obj_student.gender = data['gender']
        obj_student.birthday = data['birthday']
        obj_student.mobile = data['mobile']
        obj_student.email = data['email']
        obj_student.address = data['address']
        obj_student.image = data['image']
        # 保存
        obj_student.save()
        # 使用ORM获取所有学生信息 并把对象转为字典格式
        obj_students = Student.objects.all().values()
        # 把外层的容器转为List
        students = list(obj_students)
        # 返回
        return JsonResponse({'code': 1, 'data': students})
    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "修改保存到数据库出现异常，具体原因：" + str(e)})


def delete_student(request):
    """删除一条学生信息"""
    # 接收前端传递过来的值
    data = json.loads(request.body.decode("utf-8"))
    try:
        # 查找到要修改的学生信息
        obj_student = Student.objects.get(sno=data['sno'])
        # 删除
        obj_student.delete()
        # 使用ORM获取所有学生信息 并把对象转为字典格式
        obj_students = Student.objects.all().values()
        # 把外层的容器转为List
        students = list(obj_students)
        # 返回
        return JsonResponse({'code': 1, 'data': students})
    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "删除学生信息写入数据库出现异常，具体原因：" + str(e)})


def delete_students(request):
    """批量删除学生信息"""
    # 接收前端传递过来的值
    data = json.loads(request.body.decode("utf-8"))
    try:
        # 遍历传递的集合
        for one_student in data['student']:
            # 查询当前记录
            obj_student = Student.objects.get(sno=one_student['sno'])
            # 执行删除
            obj_student.delete()
        # 使用ORM获取所有学生信息 并把对象转为字典格式
        obj_students = Student.objects.all().values()
        # 把外层的容器转为List
        students = list(obj_students)
        # 返回
        return JsonResponse({'code': 1, 'data': students})
    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "批量删除学生信息写入数据库出现异常，具体原因：" + str(e)})


class SchoolAvatarUploadView(APIView):
    """上传头像"""

    def post(self, request):
        """接收上传的文件"""
        # 接收上传的文件
        rev_file = request.data.get('avatar')
        print(rev_file)
        # 判断，是否有文件
        if not rev_file:
            return Response({'code': 0, 'msg': '图片不存在！'})
        # 获得一个唯一的名字： uuid +hash
        new_name = get_random_str()
        # 准备写入的URL
        file_path = os.path.join(settings.MEDIA_ROOT, 'avatars', new_name + os.path.splitext(rev_file.name)[1])
        print(file_path)
        # 开始写入到本次磁盘
        try:
            f = open(file_path, 'wb')
            # 多次写入
            for i in rev_file.chunks():
                f.write(i)
            # 要关闭
            f.close()
            # 返回
            return Response({'code': 1, 'name': new_name + os.path.splitext(rev_file.name)[1]})

        except Exception as e:
            return Response({'code': 0, 'msg': str(e)})


def get_random_str():
    #获取uuid的随机数
    uuid_val = uuid.uuid4()
    #获取uuid的随机数字符串
    uuid_str = str(uuid_val).encode('utf-8')
    #获取md5实例
    md5 = hashlib.md5()
    #拿取uuid的md5摘要
    md5.update(uuid_str)
    #返回固定长度的字符串
    return md5.hexdigest()


# def import_students_excel(request):
#     """从Excel批量导入学生信息"""
#     # ========1. 接收Excel文件存储到Media文件夹 =======
#     rev_file = request.FILES.get('excel')
#     # 判断，是否有文件
#     if not rev_file:
#         return JsonResponse({'code': 0, 'msg': 'Excel文件不存在！'})
#     # 获得一个唯一的名字： uuid +hash
#     new_name = get_random_str()
#     # 准备写入的URL
#     file_path = os.path.join(settings.MEDIA_ROOT, new_name + os.path.splitext(rev_file.name)[1])
#     # 开始写入到本次磁盘
#     try:
#         f = open(file_path, 'wb')
#         # 多次写入
#         for i in rev_file.chunks():
#             f.write(i)
#         # 要关闭
#         f.close()
#     except Exception as e:
#         return JsonResponse({'code': 0, 'msg': str(e)})
#
#     #====== 2. 读取存储在Media文件夹的数据  =====
#     ex_students = read_excel_dict(file_path)
#
#     # ====3. 把读取的数据存储到数据库 =====
#     # 定义几个变量： success:  error: errors
#     success = 0
#     error = 0
#     error_snos = []
#
#     # 开始遍历
#     for one_student in ex_students:
#         try:
#
#             obj_student = Student.objects.create(sno=one_student['sno'], name=one_student['name'],
#                                                  gender=one_student['gender'],
#                                                  birthday=one_student['birthday'], mobile=one_student['mobile'],
#                                                  email=one_student['email'], address=one_student['address'])
#             # 计数
#             success += 1
#         except:
#             # 如果失败了
#             error += 1
#             error_snos.append(one_student['sno'])
#
#     # 4. 返回--导入信息（成功：5，失败：4--（sno））,所有学生
#     obj_students = Student.objects.all().values()
#     students = list(obj_students)
#     return JsonResponse({'code': 1, 'success': success, 'error': error, 'errors': error_snos, 'data': students})

logging.basicConfig(level=logging.INFO, filename='import_students_log.txt',
                    format='%(asctime)s - %(levelname)s - %(message)s')


def import_students_excel(request):
    """从 Excel 批量导入学生信息"""
    # ========1. 接收 Excel 文件存储到 Media 文件夹 =======
    rev_file = request.FILES.get('excel')
    logging.info(f"接收到的文件名称：{rev_file.name if rev_file else '无文件'}")
    # 判断，是否有文件
    if not rev_file:
        logging.error("Excel 文件不存在！")
        return JsonResponse({'code': 0, 'sg': 'Excel 文件不存在！'})
    # 获得一个唯一的名字：uuid + hash
    new_name = get_random_str()
    # 准备写入的 URL
    file_path = os.path.join(settings.MEDIA_ROOT, new_name + os.path.splitext(rev_file.name)[1])
    # 开始写入到本次磁盘
    try:
        f = open(file_path, 'wb')
        # 多次写入
        for i in rev_file.chunks():
            f.write(i)
        # 要关闭
        f.close()
    except Exception as e:
        logging.error(f"文件写入磁盘时发生错误: {str(e)}")
        return JsonResponse({'code': 0, 'sg': str(e)})

    #====== 2. 读取存储在 Media 文件夹的数据  =====
    logging.info("开始读取存储在 Media 文件夹的数据")
    ex_students = read_excel_dict(file_path)

    # ====3. 把读取的数据存储到数据库 =====
    # 定义几个变量： success:  error: errors
    success = 0
    error = 0
    error_snos = []
    errorreason = 0

    # 开始遍历
    for one_student in ex_students:
        try:
            logging.info(f"正在处理学生数据: {one_student}")
            obj_student = Student.objects.create(sno=one_student['sno'], name=one_student['name'],
                                                 gender=one_student['gender'],
                                                 birthday=one_student['birthday'], mobile=one_student['mobile'],
                                                 email=one_student['email'], address=one_student['address'],
                                                 school_id='1')
            # 计数
            success += 1
        except Exception as e:
            # 如果失败了
            error += 1
            errorreason = str(e)
            error_snos.append(one_student['sno'])
            logging.error(f"插入学生数据 {one_student['sno']} 时发生错误: {str(e)}")

    # 4. 返回--导入信息（成功：5，失败：4--（sno））,所有学生
    obj_students = Student.objects.all().values()
    students = list(obj_students)
    return JsonResponse(
        {'code': 1, 'uccess': success, 'error': error, 'errors': error_snos, 'data': students, 'msg': errorreason})


def export_student_excel(request):
    """导出数据到excel"""
    # 获取所有的学生信息
    obj_students = Student.objects.all().values()
    # 转为List
    students = list(obj_students)
    # 准备名称
    excel_name = get_random_str() + ".xlsx"
    # 准备写入的路劲
    path = os.path.join(settings.MEDIA_ROOT, excel_name)
    # 写入到Excel
    write_to_excel(students, path)
    # 返回
    return JsonResponse({'code': 1, 'name': excel_name})


def read_excel_dict(path: str):
    """读取Excel数据，存储为字典 --- [{},{},{},]"""
    # 实例化一个wrokbook
    workbook = openpyxl.load_workbook(path)
    # 实例化一个sheet
    sheet = workbook['student']
    # 定义一个变量存储最终的数据--[]
    students = []
    # 准备key
    keys = ['sno', 'name', 'gender', 'birthday', 'mobile', 'email', 'address']
    # 遍历
    for row in sheet.rows:
        # 定义一个临时的字典
        temp_dict = {}
        # 组合值和key
        for index, cell in enumerate(row):
            # 组和
            temp_dict[keys[index]] = cell.value
        # 附加到list中
        students.append(temp_dict)
    #返回
    return students


def write_to_excel(data: list, path: str):
    """把数据库写入到Excel"""
    # 实例化一个workbook
    workbook = openpyxl.Workbook()
    # 激活一个sheet
    sheet = workbook.active
    # 为sheet命名
    sheet.title = 'student'
    # 准备keys
    keys = data[0].keys()
    # 准备写入数据
    for index, item in enumerate(data):
        # 遍历每一个元素
        for k, v in enumerate(keys):
            sheet.cell(row=index + 1, column=k + 1, value=str(item[v]))
    # 写入到文件
    workbook.save(path)


class AplyListView(APIView):
    def post(self, request):
        data = request.data.get('status')
        try:
            payload = request.user
            username = payload['username']
            school_id = payload['id']
            print('查找的申请：', data)
            # 使用ORM获取所有学生信息
            queryset = Application.objects.filter(Q(school_id=school_id) & Q(status=data))
            # 使用序列化器序列化查询集
            serializer = ApplicationSerializer(queryset, many=True)
            # 返回序列化后的数据
            return Response({'code': 1, 'data': serializer.data})
        except Exception as e:
            # 如果出现异常，返回错误信息
            return Response({'code': 0, 'msg': "获取申请列表出现异常，具体错误：" + str(e)})


class AgreeView(APIView):
    def post(self, request):
        data = json.loads(request.body.decode("utf-8"))
        try:
            obj_application = Application.objects.get(id=data['id'])
            obj_application.status = data['status']
            obj_application.save()
            serializer = ApplicationSerializer(obj_application, many=True)
            return Response({'code': 1, 'data': serializer.data})
        except Exception as e:
            return JsonResponse({'code': 0, 'msg': "status修改异常，具体原因：" + str(e)})
    # 如果出现异常，返回错误信息


class SchoolListView(APIView):
    def get(self, request):
        try:
            payload = request.user
            school_id = payload['id']
            school = School.objects.get(id=school_id)
            serializer = SchoolSerializer(school, many=False)
            print(serializer.data)
            return Response({'code': 1, 'data': serializer.data})
        except Exception as e:
            return Response({'code': 0, 'msg': "获取学校信息出现异常，具体错误：" + str(e)})

    def post(self, request):
        data = request.data.get('image')
        try:
            print('上传的图片：', data)
            payload = request.user
            school_id = payload['id']
            school = School.objects.get(id=school_id)
            school.image = data
            school.save()
            serializer = SchoolSerializer(school, many=False)
            return Response({'code': 1, 'data': serializer.data})
        except Exception as e:
            return Response({'code': 0, 'msg': "修改学校信息出现异常，具体错误：" + str(e)})
    # def delete(self, request):


class SchoolNoticeListView(APIView):
    def post(self, request):
        payload = request.user
        school_id = payload['id']
        school = School.objects.get(id=school_id)
        content = request.data.get('content')
        title = request.data.get('title')
        rev_file = request.data.get('image')
        # 判断，是否有文件
        if not rev_file:
            return Response({'code': 0, 'msg': '图片不存在！'})
        # 获得一个唯一的名字： uuid +hash
        new_name = get_random_str()
        # 准备写入的URL
        file_path = os.path.join(settings.MEDIA_ROOT, 'noti_img', new_name + os.path.splitext(rev_file.name)[1])
        # 开始写入到本次磁盘
        try:
            f = open(file_path, 'wb')
            # 多次写入
            for i in rev_file.chunks():
                f.write(i)
            # 要关闭
            f.close()
            # 返回
            SchoolNotification = Snotification.objects.create(school=school, content=content,
                                                              title=title,
                                                              img=new_name + os.path.splitext(rev_file.name)[1])
            return Response({'code': 1001, 'name': new_name + os.path.splitext(rev_file.name)[1]})
        except Exception as e:
            return Response({'code': -1, 'msg': str(e)})

    def get(self, request):
        payload = request.user
        school_id = payload['school_id']
        school = School.objects.get(id=school_id)
        try:
            notices = Snotification.objects.filter(school=school).order_by('-created_at').first()
            serializer = NotificationSerializer(notices, many=False)
        except Exception as e:
            return Response({'code': -1, 'msg': str(e)})
        return Response({'code': 1001, 'data': serializer.data})


class ApplyListView(APIView):

    def post(self, request):
        print(request.data)
        serializer = ApplicationSerializer(data=request.data)
        if serializer.is_valid():
            # 保存实例并获取创建的实例
            instance = serializer.save()
            # 获取实例的ID
            instance_id = instance.id
            return Response({'code': 1001, 'data': instance_id}, )
        print(serializer.errors)
        return Response({'code': -1, 'msg': serializer.errors})

    def get(self, request):
        try:
            payload = request.user
            school_id = payload['id']  # 确保 payload 结构正确且包含 id

            # 获取学校
            school = School.objects.get(id=school_id)

            # 获取与学校相关的申请
            queryset = Application.objects.filter(student_name__school=school)

            # 序列化申请
            serializer = ApplicationSerializer(queryset, many=True)

            return Response({'code': 1001, 'data': serializer.data})

        except School.DoesNotExist:
            return Response({'code': 1002, 'message': '学校不存在'}, status=404)
        except Exception as e:
            return Response({'code': 1003, 'message': str(e)}, status=500)


class UploadApplyImageView(APIView):

    def post(self, request):
        data = request.data
        id = data.get('id')
        apply = Application.objects.get(id=id)
        description = data.get('description')
        rev_file = request.data.get('image')
        # 判断，是否有文件
        if not rev_file:
            return Response({'code': 0, 'msg': '图片不存在！'})
        # 获得一个唯一的名字： uuid +hash
        new_name = get_random_str()
        # 准备写入的URL
        file_path = os.path.join(settings.MEDIA_ROOT, 'ap_img', new_name + os.path.splitext(rev_file.name)[1])

        try:
            f = open(file_path, 'wb')
            # 多次写入
            for i in rev_file.chunks():
                f.write(i)
            # 要关闭
            f.close()
            # 返回
            # product.image = new_name + os.path.splitext(rev_file.name)[1]
            # product.save()
            Proofs.objects.create(application=apply, description=description,
                                  url='http://192.168.43.200:8000/media/ap_img/' + new_name +
                                      os.path.splitext(rev_file.name)[1])
            return Response({'code': 1001, 'name': new_name + os.path.splitext(rev_file.name)[1]})
        except Exception as e:
            return Response({'code': -1, 'msg': str(e)})


class AgreeApView(APIView):
    def post(self, request):
        id = request.data.get('id')
        identity = request.data.get('identity')
        print(id, identity)
        try:
            obj_application = Application.objects.get(id=id)
            student = obj_application.student_name
            print(student)
            student.identity = identity
            student.save()
            print(student.identity)
            obj_application.status = '已批准'
            obj_application.save()
            serializer = ApplicationSerializer(obj_application, many=True)
            return Response({'code': 1, 'data': serializer.data})
        except Exception as e:
            return Response({'code': -1, 'msg': str(e)})


class RejectApView(APIView):
    def post(self, request):
        data = request.data.get('status')
        try:
            obj_application = Application.objects.get(id=data['id'])
            obj_application.status = '已拒绝'
            obj_application.save()
            serializer = ApplicationSerializer(obj_application, many=True)
            return Response({'code': 1, 'data': serializer.data})
        except Exception as e:
            return Response({'code': -1, 'msg': str(e)})


class SigninView(APIView):
    def post(self, request):
        payload = request.user
        school_id = payload['id']
        school = School.objects.get(id=school_id)
        data = request.data
        account = data.get('account')
        password = data.get('password')
        if School.objects.filter(account=account).exists():
            return Response({'code': -1, 'msg': '账号已存在'})
        new_school = School.objects.create(account=account, password=password, name=request.data.get('name'))
        apply = SchoolApplication.objects.filter(school_name=new_school.name)
        print(new_school.name)
        SchoolApplication.objects.filter(school_name=new_school.name).update(status='通过')
        # apply.save()
        return Response({'code': 1001, 'msg': '注册成功'})

    def get(self, request):
        schoolapply = SchoolApplication.objects.all()
        serializer = SchoolApplicationSerializer(schoolapply, many=True)
        return Response({'code': 1002, 'data': serializer.data})


class SignupView(APIView):
    authentication_classes = []

    def post(self, request):
        data = request.data
        print(data)
        rev_file = request.FILES.get('file')  # 使用 request.FILES 获取文件
        schoolName = data.get('schoolName')
        email = data.get('email')
        applicantNumber = data.get('applicantNumber')
        address = data.get('address')

        # 判断，是否有文件
        if not rev_file:
            return Response({'code': 0, 'msg': '图片不存在！'})

            # 获得一个唯一的名字： uuid +hash
        new_name = get_random_str()
        file_path = os.path.join(settings.MEDIA_ROOT, 'sc_img', new_name + os.path.splitext(rev_file.name)[1])
        print(file_path)  # 检查文件路径

        try:
            # 开始写入到本次磁盘
            with open(file_path, 'wb') as f:
                for chunk in rev_file.chunks():
                    f.write(chunk)

                    # 保存数据
            SchoolApplication.objects.create(
                school_name=schoolName,
                email=email,
                mobile=applicantNumber,
                address=address,
                image='http://192.168.43.200:8000/media/sc_img/'+new_name + os.path.splitext(rev_file.name)[1],
                status='待审核'
            )
            return Response({'code': 1001, 'name': new_name + os.path.splitext(rev_file.name)[1]})
        except Exception as e:
            return Response({'code': -1, 'msg': str(e)})

class SchoolView(APIView):
    def get(self, request):
        payload = request.user
        school_id = payload['id']
        school = School.objects.get(id=school_id)
        serializer = SchoolSerializer(school, many=False)
        return Response({'code': 1001, 'data': serializer.data})
    def put(self, request):
        data = request.query_params
        payload = request.user
        school_id = payload['id']
        school = School.objects.get(id=school_id)
        school.account = data.get('username')
        school.address = data.get('address')
        school.name = data.get('name')
        school.email = data.get('email')
        school.save()
        serializer = SchoolSerializer(school, many=False)
        return Response({'code': 1001, 'data': serializer.data})